import * as THREE from 'three';
import axios from "axios"
import { Lut } from 'three/examples/jsm/math/Lut';
import { dataFiles } from '../mockData';
const colorKeyCode = 'PointColor';
const lut = new Lut();
const Service = axios.create({
  timeout: 1000 * 60 * 20,
  baseURL: '',
  headers: {
    'Content-Type': 'application/json',
  },
});
Service.interceptors.response.use(
  (response) => {
    if (response.status === 200) {
      let data = response.data;
      return data;
    }
  },
  (error) => {
    // return Promise.reject(new BSError(Code.NETWORK_ERROR, 'Network Error'));
  },
);
export function getColorTable(count = 64, seed) {
  const colors = getThemeColor(seed);
  const len = colors.length - 1;
  const lookupTable = colors.map((color, index) => {
      return [index / len, color];
  });
  lut.addColorMap(colorKeyCode, lookupTable);
  lut.setColorMap(colorKeyCode, count);
  const table = lut.lut.slice(0, count);
  return table;
}

export function getThemeColor(seed) {
  return ['#00ff00', '#ffff00', '#ff0000'];
}

export function getShaderCode(
  option = { hasIntensity: false, hasVelocity: false, hasRGB: false },
) {
  let defines = [];
  if (option.hasIntensity) defines.push('#define FLAG_INTENSITY');
  if (option.hasRGB) defines.push('#define FLAG_COLOR');
  if (option.hasVelocity) defines.push('#define FLAG_V');
  let vertex = `
  ${defines.join('\n')}
  precision mediump float;
  precision mediump int;

  struct ColorItem {
      float min;
      float max;
      vec3 color;
  };

  struct FilterBox {
      // 0 color, 1 color filter,
      float type;
      vec3 min;
      vec3 max;
      vec3 color;
      mat4 matrix;
  };


  // color
  uniform vec3 colorTable[64];
  uniform float colorMode;
  uniform vec3 edgeColor[2];
  uniform vec3 singleColor;
  uniform float openIntensity;
  uniform float brightness;

  attribute float road;
  uniform float colorRoad;

  #ifdef FLAG_COLOR
  attribute vec3 color;
  #endif

  // intensity
  #ifdef FLAG_INTENSITY
  uniform vec2 intensityRange;
  attribute float intensity;
  #endif

  #ifdef FLAG_V
  uniform vec2 velocityRange;
  uniform vec2 pointVelocity;
  attribute float velocity;
  #endif

  // matrix
  uniform mat4 modelViewMatrix; 
  uniform mat4 projectionMatrix; 

  // 
  uniform vec2 heightRange;
  uniform vec2 pointHeight;
  uniform float pointSize; 
  // 1.0 range-only, 2.0 range-opacity
  uniform float trimType; 

  // filter box
  uniform float hasFilterBox;
  uniform FilterBox boxInfo;

  // camera region
  uniform float hasCameraRegion;
  uniform mat4 regionMatrix;

  attribute vec3 position;
  //attribute vec4 color;

  varying vec3 vColor;
  varying float vOpacity;

  bool isInBox(vec3 pos, vec3 min, vec3 max){
      return pos.x >= min.x && pos.x <= max.x && pos.y >= min.y && pos.y <= max.y && pos.z >= min.z && pos.z <= max.z;
  }

  vec3 getColor(float value){
      vec3 color = vec3(1,0,0);
      float min = pointHeight.x;
      float max = pointHeight.y;
      if(colorRoad>0.0) min = 0.0;

      if(colorRoad>0.0&&road>0.0){
        color = edgeColor[0];
      } else if(value <= min){
          color = edgeColor[0];
      }else if(value >= max){
          color = edgeColor[1];
      }else{
          float alpha = (value-min) / (max-min);
          int index = int(floor(alpha * 64.0));
          if(index==64) index = 63;
          color = colorTable[index];
      }
      return color;
  }

  vec3 getColorByV(float value, vec2 vValue){
      vec3 c1 = edgeColor[0];
      vec3 c2 = edgeColor[1];
      if(value<vValue.x){
          return c1;
      }
      if(value>vValue.y){
          return c2;
      }
      float total = vValue.y - vValue.x;
      float alpha = (value - vValue.x) / total;
      c1.r = c1.r+(c2.r-c1.r)*alpha;
      c1.g = c1.g+(c2.g-c1.g)*alpha;
      c1.b = c1.b+(c2.b-c1.b)*alpha;
      return c1;
  }


  void main()	{

      vOpacity = 1.0;
      float vDiscard = -1.0;
      float vPointSize = pointSize;
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
      if(position.z>heightRange.y||position.z<heightRange.x){
          vDiscard = 1.0;  
      }
      
      if (colorMode == 1.0)
      {
          if(colorRoad>0.0&&road>0.0){
              vColor = edgeColor[0];
          } else {
              vColor = singleColor;
          }

      } else if(colorMode == 2.0)
      {
          #ifdef FLAG_COLOR
          vColor = color / 255.0;
          #endif
      } else if(colorMode == 3.0) {
          #ifdef FLAG_V
          vColor = getColorByV(velocity, pointVelocity);
          if(velocity!=0.0){
              vPointSize+=2.0;
          }
          #endif
      } else {
          vColor = getColor(position.z);
      }
      if(openIntensity > 0.0){
          #ifdef FLAG_INTENSITY
          if(intensityRange.x > intensity || intensityRange.y < intensity){
              vDiscard = 1.0;  
          }else {
              vColor *= intensity / 10.0;
          }
          #endif
          
      }

      if(hasCameraRegion > 0.0){
          vec4 posNor = regionMatrix * vec4( position, 1.0 );
          posNor.xyz = posNor.xyz/posNor.w;
          if( isInBox(posNor.xyz, vec3(-1.0,-1.0,-1.0),vec3(1.0,1.0,1.0))){
              vColor = vec3(1.0,1.0,1.0);
          }

      }

      if(hasFilterBox > 0.0){
          vec4 boxPos = boxInfo.matrix *  vec4( position, 1.0 );
          //type: 0 color, 1 color filter,
          float type = boxInfo.type;
          if(type == 0.0){
              if(isInBox(boxPos.xyz,boxInfo.min,boxInfo.max)){
                  vColor = boxInfo.color;
              }
          }else if(type == 1.0){
              if(isInBox(boxPos.xyz,boxInfo.min,boxInfo.max)){
                  vColor = boxInfo.color;
              }else{
                  // gl_Position = vec4(2.0);
                  vDiscard = 1.0;
              }
          }
          
      }
      vColor *= brightness;
      gl_PointSize = vPointSize;
      if(vDiscard > 0.0) {
          gl_Position = vec4(2.0,2.0,2.0,1.0);
          vOpacity = 0.0;
      }

  }`;

  let frag = `
  precision mediump float;
  precision mediump int;

  varying vec3 vColor;
  varying float vOpacity;

  void main()	{
      gl_FragColor = vec4(vColor*vOpacity,vOpacity);

  }`;

  return { vertex, frag };
}

export function isMatrixColumnMajor(elements) {
  let rightZero = elements[3] === 0 && elements[7] === 0 && elements[11] === 0;
  let bottomHasOne = !!elements[12] || !!elements[13] || !!elements[14];
  return rightZero && bottomHasOne;
}

export function translateCameraConfig(info) {
  let cameraExternal = info?.cameraExternal || info?.camera_external;
  let cameraInternal = info?.cameraInternal || info?.camera_internal;

  if (!info || !cameraExternal || cameraExternal.length !== 16) return null;

  // to rowMajor
  if (info.rowMajor === false || isMatrixColumnMajor(cameraExternal)) {
      let matrix = new THREE.Matrix4();
      matrix.elements = cameraExternal;
      matrix.transpose();
      cameraExternal = matrix.elements;
  }

  return { cameraExternal, cameraInternal };
}

export function createViewConfig(fileConfig, cameraInfo) {
  let viewConfig = []
  let pointsUrl = '';
  const regLidar = new RegExp(/point(_?)cloud/i);
  const regImage = new RegExp(/image/i);
  fileConfig.forEach((e) => {
    if (regLidar.test(e.dirName)) {
      pointsUrl = e.url;
    } else if (regImage.test(e.dirName)) {
      const index = +(e.dirName.match(/[0-9]{1,5}$/))[0];
      viewConfig[index] = {
        cameraInternal: { fx: 0, fy: 0, cx: 0, cy: 0 },
        cameraExternal: [],
        imgSize: [0, 0],
        imgUrl: e.url,
        name: e.name,
        imgObject: null,
      };
    }
  });
  viewConfig = viewConfig.filter((e) => !!e);
  viewConfig.forEach((config, index) => {
    let info = cameraInfo[index];

    let translateInfo = translateCameraConfig(info);
    if (!translateInfo) return;

    config.cameraExternal = translateInfo.cameraExternal;
    config.cameraInternal = translateInfo.cameraInternal;
    config.imgSize = [info.width, info.height];
    // config.rowMajor = info.rowMajor;
  });
  // filter
  viewConfig = viewConfig.filter((e) => e.cameraExternal.length === 16 && e.cameraInternal);
  // console.log(viewConfig, "得到viewConfig");
  return { pointsUrl, config: viewConfig };
}

export async function loadFrameConfig() {
  const regLidar = new RegExp(/point(_?)cloud/i);
  const regConfig = new RegExp(/camera(_?)config/i);
  // let { configs: fileConfig, name } = await api.getDataFile(data.id + '');
  // console.log(dataFiles, "获取相机配置");
  if (dataFiles.filter((e) => regLidar.test(e.dirName)).length === 0) {
    throw this.editor.lang('no-point-data');
  }
  let cameraConfig = dataFiles.find((e) => regConfig.test(e.dirName));
  // console.log(cameraConfig, "获取相机配置loadFrameConfig");
  // let resource = this.editor.dataResource.getResource(frame);
  let cameraInfo = [];
  if (cameraConfig) {
    cameraInfo = await Service.request({
      url: cameraConfig.url,
      method: 'get',
      params: null,
      headers: { 'x-request-type': 'resource' },
    })
    // cameraInfo = await api.getUrl(cameraConfig.url);
  }
  let info = createViewConfig(dataFiles, cameraInfo);
  // console.log(info, "info");
  let config = {
    pointsUrl: info.pointsUrl,
    pointsData: {},
    viewConfig: info.config,
    time: 0,
    name: '09',
  };
  // console.log(config, "哈哈哈之前");
  return config;
}